#include <raw_api.h>


void event_init(void) 
{

	ACTIVE_EVENT_STRUCT *temp;
	RAW_U8 i;

	/*Init idle task queue information, MAX_IDLE_EVENT_TASK max 64 is allowed*/
	for (i = 0; i <= MAX_IDLE_EVENT_TASK - 1; i++) {
		temp = active_idle_task[i].act;

		RAW_ASSERT(temp != 0); 
		
		temp->prio = i;
		temp->head    = 0;
		temp->tail    = 0;
		temp->nUsed   = 0;

		temp->priority_x = i & 0x7;
		temp->priority_y = i >> 3;
		
		temp->priority_bit_y = (RAW_U8)(1 << temp->priority_y);
		temp->priority_bit_x = (RAW_U8)(1 << temp->priority_x);

	}

	/*Init the list*/
	list_init(&raw_idle_tick_head);

}


static RAW_U16 event_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para, RAW_U8 opt_send_method)
{

 	RAW_SR_ALLOC();
	
	ACTIVE_EVENT_STRUCT_CB *acb = &active_idle_task[me->prio];
	
	RAW_CPU_DISABLE();

	if (me->nUsed == acb->end) {

		RAW_CPU_ENABLE();
		return RAW_IDLE_EVENT_EXHAUSTED;
	}
	

	if (opt_send_method == SEND_TO_END) {
		
		acb->queue[me->head].sig = sig;

		acb->queue[me->head].para = para;

		me->head++;

		if (me->head == acb->end) {   
			
			me->head = 0;
			
		}   
	}

	else {

		if (me->tail == 0) { 			   
			me->tail = acb->end;
		}

		me->tail--;

		acb->queue[me->tail].sig = sig;

		acb->queue[me->tail].para = para;

	}
	
	++me->nUsed;
	
	if (me->nUsed == 1) {             
		
		raw_idle_rdy_grp |= acb->act->priority_bit_y;
		raw_rdy_tbl[acb->act->priority_y] |= acb->act->priority_bit_x;

	}

	RAW_CPU_ENABLE();

	return RAW_SUCCESS;

   	
}


/*
************************************************************************************************************************
*                                      Post an event (FIFO) to idle task
*
* Description: This function is called to post an event to idle task, it might be called in interrupt.
*
* Arguments  :me is the address of ACTIVE_EVENT_STRUCT
*                    -----
*                    sig is the signal which want to be posted to idle task
*		         -----
*                    para is the parameter which want to be posted to idle task. 
*
* Returns	RAW_SUCCESS: raw os return success		
*                   RAW_IDLE_EVENT_EXHAUSTED: No more msg to me.
*						
* Note(s)    	
*
*             
************************************************************************************************************************
*/
RAW_U16 event_end_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para)
{

	return event_post(me, sig, para, SEND_TO_END);

}


/*
************************************************************************************************************************
*                                      Post an event (LIFO) to idle task
*
* Description: This function is called to post an event to idle task, it might be called in interrupt.
*
* Arguments  :me is the address of ACTIVE_EVENT_STRUCT
*                    -----
*                    sig is the signal which want to be posted to idle task
*		         -----
*                    para is the parameter which want to be posted to idle task. 
*
* Returns	RAW_SUCCESS: raw os return success		
*                   RAW_IDLE_EVENT_EXHAUSTED: No more msg to me.
*						
* Note(s)    	
*
*             
************************************************************************************************************************
*/
RAW_U16 event_front_post(ACTIVE_EVENT_STRUCT *me, RAW_U16 sig, void *para)
{
	
	return event_post(me, sig, para, SEND_TO_FRONT);

}



void event_tick_isr() {

	ACTIVE_EVENT_STRUCT *a;
	
	LIST *head;
	LIST *iter;
	LIST *iter_temp;

	head = &raw_idle_tick_head;
	iter = head->next;

	/*if list is not empty*/
 	while (iter != head) {

		a =  list_entry(iter, ACTIVE_EVENT_STRUCT, idle_tick_list);
		iter_temp =  iter->next;

		if (a->tick_ctr) {
			--a->tick_ctr;
			
			if (a->tick_ctr == 0) {
				list_delete(iter);
				event_end_post(a, STM_TIMEOUT_SIG, 0);
			}
		}
		
		iter = iter_temp;
 	}

	
}


RAW_U16 event_tick_arm(ACTIVE_EVENT_STRUCT *me, RAW_TICK_TYPE ticks)
{
	RAW_U16 tick_ret;

	RAW_SR_ALLOC();

	if (ticks == 0) {

		return RAW_IDLE_TICK_ADD_FAILED;
	}

	RAW_CPU_DISABLE();

	if (me->tick_ctr == 0) {
		me->tick_ctr = ticks;
		list_insert(&raw_idle_tick_head, &me->idle_tick_list);	
		tick_ret = RAW_SUCCESS;
	}

	else {
		tick_ret = RAW_IDLE_TICK_ADD_FAILED;
	}

	RAW_CPU_ENABLE();

	return tick_ret;

}

RAW_U16 event_tick_disarm(ACTIVE_EVENT_STRUCT *me)
{
	RAW_U16 tick_ret;

	RAW_SR_ALLOC();

	RAW_CPU_DISABLE();

	if (me->tick_ctr) {

		list_delete(&me->idle_tick_list);
		me->tick_ctr = 0;
		tick_ret = RAW_SUCCESS;
	}

	else {

		tick_ret = RAW_IDLE_TICK_DELETE_FAILED;
	}

	RAW_CPU_ENABLE();

	return tick_ret;
	
}

void event_sche() 
{
    ACTIVE_EVENT_STRUCT *a;
	STATE_EVENT temp;
	
	ACTIVE_EVENT_STRUCT_CB *acb;
	RAW_U8 y;
	RAW_U8 idle_high_priority;
	
	RAW_SR_ALLOC();

	while (1) { 
		
		RAW_CPU_DISABLE();

		/*if get events then process it*/
		if (raw_idle_rdy_grp) {

			y = raw_idle_map_table[raw_idle_rdy_grp];
			idle_high_priority = ((y << 3) + raw_idle_map_table[raw_rdy_tbl[y]]);
           
			acb = &active_idle_task[idle_high_priority];
			a = active_idle_task[idle_high_priority].act;

			--a->nUsed;
			
			if (a->nUsed == 0) {         
		
				raw_rdy_tbl[a->priority_y] &= (RAW_U8)~a->priority_bit_x;
				
				if (raw_rdy_tbl[a->priority_y] == 0) {                      /* Clear event grp bit if this was only task pending */
					raw_idle_rdy_grp &= (RAW_U8)~a->priority_bit_y;
				}
			}
			
			temp.sig = acb->queue[a->tail].sig;

			temp.arg = acb->queue[a->tail].para;

			a->tail++;

			if (a->tail == acb->end) {                  
			    a->tail = 0;
			}

			RAW_CPU_ENABLE();

			#if (RAW_FSM_ACTIVE > 0)
			
			fsm_exceute(&a->super, &temp);                    
			
			#else
			
			hsm_exceute(&a->super, &temp);                   
			
			#endif
			
		}

		else {

			RAW_CPU_ENABLE();

//			RAW_CPU_DISABLE();

			if (raw_idle_rdy_grp == 0) {
				
				event_user();
			}
		
//			RAW_CPU_ENABLE();
			
		}
		
    }
   
}

